home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uupc11ys.zip / UUCICO / COMM.ASM < prev    next >
Assembly Source File  |  1992-03-21  |  34KB  |  1,265 lines

  1.     TITLE    COM_PKG2 -- Last updated 10/6/85
  2.     PAGE    75,132
  3. ;
  4. ; Modified to use COM1 thru COM4 - William W. Plummer, 2/21/91
  5. ; Eliminate (incomplete) support for DOS1 - William W. Plummer, 11/13/90
  6. ;
  7. ;    modified to use MSC calling sequence.
  8. ;    jrr 3/86
  9. ;
  10. ; Communications Package for the IBM PC, XT, AT and PCjr
  11. ; and strict compatibles.
  12. ; May be copied and used freely -- This is a public domain program
  13. ; Developed by Richard Gillmann, John Romkey, Jerry Saltzer,
  14. ; Craig Milo Rogers, Dave Mitton and Larry Afrin.
  15. ;
  16. ; We'd sure like to see any improvements you might make.
  17. ; Please send all comments and queries about this package
  18. ; to GILLMANN@USC-ISIB.ARPA
  19. ;
  20. ; o Supports both serial ports simultaneously
  21. ; o All speeds to 19200 baud
  22. ; o Compatible with PC, XT, AT and PCjr.
  23. ; o Built in XON/XOFF flow control option
  24. ; o Assembly language calling conventions
  25. ; o Logs all comm errors
  26. ; o Direct connect or modem protocol
  27. ;
  28. ; MAXIMUM BUFFER SIZES
  29. R_SIZE    EQU    2048        ; SIZE OF RECEIVE BUFFERS skl/88-05-13
  30. S_SIZE    EQU    4096        ; SIZE OF TRANSMIT BUFFERS ahd 01/92
  31. ; INTERRUPT NUMBERS
  32. INT_COM1 EQU    0CH        ; COM1: FROM 8259
  33. INT_COM2 EQU    0BH        ; COM2: FROM 8259
  34. INT_COM3 EQU    0CH        ; COM3: FROM 8259
  35. INT_COM4 EQU    0BH        ; COM4: FROM 8259
  36. ; 8259 PORTS
  37. INTA00    EQU    20H        ; 8259A PORT, A0 = 0
  38. INTA01    EQU    21H        ; 8259A PORT, A0 = 1
  39. ; COM1: & COM3: LEVEL 4
  40. IRQ4    EQU    2*2*2*2         ; 8259A OCW1 MASK, M4=1, A0=0
  41. NIRQ4    EQU    NOT IRQ4 AND 0FFH    ; COMPLEMENT OF ABOVE
  42. EOI4    EQU    4 OR 01100000B        ; 8259A OCW2 SPECIFIC IRQ4 EOI, A0=0
  43. ; COM2: & COM4: LEVEL 3
  44. IRQ3    EQU    2*2*2            ; 8259A OCW1 MASK, M3=1, A0=0
  45. NIRQ3    EQU    NOT IRQ3 AND 0FFH    ; COMPLEMENT OF ABOVE
  46. EOI3    EQU    3 OR 01100000B        ; 8259A OCW2 SPECIFIC IRQ3 EOI, A0=0
  47.  
  48. ; FLOW CONTROL CHARACTERS
  49. CONTROL_Q EQU    11H        ; XON
  50. CONTROL_S EQU    13H        ; XOFF
  51. ; MISC.
  52. DOS    EQU    21H        ; DOS FUNCTION CALLS
  53.     PAGE
  54. ;
  55. ; ROM BIOS Data Area
  56. ;
  57. RBDA    SEGMENT AT 40H
  58. RS232_BASE DW    4 DUP(?)    ; ADDRESSES OF RS232 ADAPTERS
  59. RBDA    ENDS
  60. ;
  61. ; ROM PC-Type IDENT
  62. ;
  63. ROM    SEGMENT AT 0F000H
  64.     ORG    0FFFEH
  65. ROMID    DB    ?        ; 0FFH=PC OR EARLY XT, 0FEH=XT, 0FDH=JR
  66. ROM    ENDS
  67.     PAGE
  68. ;
  69. ; TABLE FOR EACH SERIAL PORT
  70. ;
  71. SP_TAB        STRUC
  72. PORT        DB    ?    ; 1 OR 2 OR 3 OR 4
  73. ; PARAMETERS FOR THIS INTERRUPT LEVEL
  74. INT_COM     DB    ?    ; INTERRUPT NUMBER
  75. IRQ        DB    ?    ; 8259A OCW1 MASK
  76. NIRQ        DB    ?    ; COMPLEMENT OF ABOVE
  77. EOI        DB    ?    ; 8259A OCW2 SPECIFIC END OF INTERRUPT
  78. ; INTERRUPT HANDLERS FOR THIS LEVEL
  79. INT_HNDLR    DW    ?    ; OFFSET TO INTERRUPT HANDLER
  80. OLD_COM_OFF    DW    ?    ; OLD HANDLER'S OFFSET
  81. OLD_COM_SEG    DW    ?    ; OLD HANDLER'S SEGMENT
  82. ; ATTRIBUTES
  83. INSTALLED    DB    ?    ; IS PORT INSTALLED ON THIS PC? (1=YES,0=NO)
  84. BAUD_RATE    DW    ?    ; 19200 MAX
  85. CONNECTION    DB    ?    ; M(ODEM), D(IRECT)
  86. PARITY        DB    ?    ; N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
  87. STOP_BITS    DB    ?    ; 1, 2
  88. XON_XOFF    DB    ?    ; E(NABLED), D(ISABLED)
  89. ; FLOW CONTROL STATE
  90. HOST_OFF    DB    ?    ; HOST XOFF'ED (1=YES,0=NO)
  91. PC_OFF        DB    ?    ; PC XOFF'ED (1=YES,0=NO)
  92. ; ERROR COUNTS
  93. ERROR_BLOCK    DW    8 DUP(?)    ; EIGHT ERROR COUNTERS
  94. ; 8250 PORTS
  95. DATREG        DW    ?    ; DATA REGISTER
  96. IER        DW    ?    ; INTERRUPT ENABLE REGISTER
  97. IIR        DW    ?    ; INTERRUPT IDENTIFICATION REGISTER
  98. LCR        DW    ?    ; LINE CONTROL REGISTER
  99. MCR        DW    ?    ; MODEM CONTROL REGISTER
  100. LSR        DW    ?    ; LINE STATUS REGISTER
  101. MSR        DW    ?    ; MODEM STATUS REGISTER
  102. ; BUFFER POINTERS
  103. START_TDATA    DW    ?    ; INDEX TO FIRST CHARACTER IN X-MIT BUFFER
  104. END_TDATA    DW    ?    ; INDEX TO FIRST FREE SPACE IN X-MIT BUFFER
  105. START_RDATA    DW    ?    ; INDEX TO FIRST CHARACTER IN REC. BUFFER
  106. END_RDATA    DW    ?    ; INDEX TO FIRST FREE SPACE IN REC. BUFFER
  107. ; BUFFER COUNTS
  108. SIZE_TDATA    DW    ?    ; NUMBER OF CHARACTERS IN X-MIT BUFFER
  109. SIZE_RDATA    DW    ?    ; NUMBER OF CHARACTERS IN REC. BUFFER
  110. ; BUFFERS
  111. TDATA        DB    S_SIZE DUP(?)    ; SEND BUFFER
  112. RDATA        DB    R_SIZE DUP(?)    ; RECEIVE BUFFER
  113. SP_TAB        ENDS
  114. ; SP_TAB EQUATES
  115. ; WE HAVE TO USE THESE BECAUSE OF PROBLEMS WITH STRUC
  116. EOVFLOW     EQU    ERROR_BLOCK    ; BUFFER OVERFLOWS
  117. EOVRUN        EQU    ERROR_BLOCK+2    ; RECEIVE OVERRUNS
  118. EBREAK        EQU    ERROR_BLOCK+4    ; BREAK CHARS
  119. EFRAME        EQU    ERROR_BLOCK+6    ; FRAMING ERRORS
  120. EPARITY     EQU    ERROR_BLOCK+8    ; PARITY ERRORS
  121. EXMIT        EQU    ERROR_BLOCK+10    ; TRANSMISSION ERRORS
  122. EDSR        EQU    ERROR_BLOCK+12    ; DATA SET READY ERRORS
  123. ECTS        EQU    ERROR_BLOCK+14    ; CLEAR TO SEND ERRORS
  124. DLL        EQU    DATREG        ; LOW DIVISOR LATCH
  125. DLH        EQU    IER        ; HIGH DIVISOR LATCH
  126.     PAGE
  127. ;    put the data in the DGROUP segment
  128. ;    far calls enter with DS pointing to DGROUP
  129. ;
  130. DGROUP    GROUP _DATA
  131. _DATA    SEGMENT PUBLIC 'DATA'
  132. ;
  133. DIV50PC     EQU    2304        ; DIVISOR FOR 50 BAUD (PC,XT)
  134. DIV50JR     EQU    2237        ; DIVISOR FOR 50 BAUD (JR)
  135. DIV50        DW    2304        ; ACTUAL DIVISOR FOR 50 BAUD IN USE
  136. CURRENT_AREA    DW    AREA1        ; CURRENTLY SELECTED AREA
  137. ; DATA AREAS FOR EACH PORT
  138. AREA1    SP_TAB    <1,INT_COM1,IRQ4,NIRQ4,EOI4>    ; COM1 DATA AREA
  139. AREA2    SP_TAB    <2,INT_COM2,IRQ3,NIRQ3,EOI3>    ; COM2 DATA AREA
  140. AREA3    SP_TAB    <3,INT_COM3,IRQ4,NIRQ4,EOI4>    ; COM3 DATA AREA
  141. AREA4    SP_TAB    <4,INT_COM4,IRQ3,NIRQ3,EOI3>    ; COM4 DATA AREA
  142. _DATA     ENDS
  143.     PAGE
  144. COM_TEXT    SEGMENT PARA PUBLIC 'CODE'
  145.     ASSUME    CS:COM_TEXT,DS:DGROUP,ES:NOTHING
  146.  
  147.     PUBLIC    _select_port
  148.     PUBLIC    _save_com
  149.     PUBLIC    _install_com
  150.     PUBLIC    _restore_com
  151.     PUBLIC    _open_com
  152.      PUBLIC _ioctl_com
  153.     PUBLIC    _close_com
  154.     PUBLIC    _dtr_on
  155.     PUBLIC    _dtr_off
  156.     PUBLIC    _r_count
  157.     PUBLIC    _s_count
  158.     PUBLIC    _receive_com
  159.     PUBLIC    _send_com
  160.     PUBLIC    _sendi_com
  161.     PUBLIC    _send_local
  162.     PUBLIC    _break_com
  163.     PUBLIC    _com_errors
  164.     PUBLIC    _modem_status
  165.     PAGE
  166.  
  167.  
  168. ; Here's the order of calls in UUPC.  The routines in COMM.ASM are called
  169. ; from ulib.c.
  170.  
  171. ; First (when a line in system has been read?), ulib&openline calls
  172. ;        select_port()        ; Sets up CURRENT_AREA
  173. ; then,     save_com()        ; Save INT vector
  174. ; then,     install_com()        ; Init area, hook INT
  175. ; then,     open_com(&cmd, 'D', 'N', STOP*T, 'D') ; Init UART, clr bufs
  176. ; then,     dtr_on().
  177.  
  178. ; At that point the line is up and running.  UUPC calls ulib&sread()
  179. ; which calls,    receive_com();
  180.  
  181. ; And UUPC calls ulib&swrite()
  182. ; which calls,    send_com();
  183.  
  184. ; To cause an error that the receiver will see, UUPC calls ulib&ssendbrk();
  185. ; which calls,    break_com();
  186.  
  187. ; When all done with the line, UUPC calls ulib&closeline()
  188. ; which calls,    dtr_off();
  189. ; then,     close_com();
  190. ; then,     restore_com();        ; Unhook INT
  191. ; and,        stat_errors();
  192.  
  193.  
  194. ; Note that on the PC COM1 and COM3 share IRQ4, while COM2 and COM4 share IRQ3.
  195. ; BUT, only one device on a given IRQ line can be active at a time.  So it is
  196. ; sufficient for UUPC to hook whatever IRQ INT its modem is on as long as it
  197. ; unhooks it when it is done with that COM port.  COMM cannot be an installed
  198. ; device driver since it must go away when UUPC is done so that other devices
  199. ; on the same INTs will come back to life.  Also, it is OK to have a static
  200. ; CURRENT_AREA containing the current area that UUPC is using.
  201.  
  202.     PAGE
  203. ;
  204. ; SELECT WHICH PORT IS TO BE "ACTIVE"
  205. ;    [bp+6] = port number
  206. _select_port    PROC FAR
  207.     push bp
  208.     mov bp,sp
  209.     mov AX,[bp+6]    ; get aguement
  210.     CMP    AL,1        ; Port 1?
  211.      JE    SP1        ; Yes
  212.     CMP    AL,2        ; Port 2?
  213.      JE    SP2        ; Yes
  214.     CMP    AL,3        ; Port 3?
  215.      JE    SP3        ; Yes
  216.     CMP    AL,4        ; Port 4?
  217.      JE    SP4        ; Yes
  218.     INT 20H         ; N.O.T.A. ????? Halt for debugging!
  219.     ; Assume port 1 if continued
  220. SP1:    MOV    AX,OFFSET DGROUP:AREA1    ; SELECT COM1 DATA AREA
  221.     JMP    SHORT SPX    ; CONTINUE
  222. SP2:    MOV    AX,OFFSET DGROUP:AREA2    ; SELECT COM2 DATA AREA
  223.     JMP    SHORT SPX    ; CONTINUE
  224. SP3:    MOV    AX,OFFSET DGROUP:AREA3    ; SELECT COM3 DATA AREA
  225.     JMP    SHORT SPX    ; CONTINUE
  226. SP4:    MOV    AX,OFFSET DGROUP:AREA4    ; SELECT COM4 DATA AREA
  227.     ;Fall into SPX
  228. SPX:    MOV    CURRENT_AREA,AX ; SET SELECTION IN MEMORY
  229.     mov sp,bp
  230.     pop bp
  231.     RET            ; DONE
  232. _select_port    ENDP
  233.     PAGE
  234. ;
  235. ; SAVE ORIGINAL COM VECTOR
  236. ;
  237. _save_com    PROC FAR
  238.     push bp
  239.     mov bp,sp
  240.     push si
  241.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  242.     PUSH    ES        ; SAVE EXTRA SEGMENT
  243.     MOV    AREA1.INT_HNDLR,OFFSET INT_HNDLR1
  244.     MOV    AREA2.INT_HNDLR,OFFSET INT_HNDLR2
  245.     MOV    AREA3.INT_HNDLR,OFFSET INT_HNDLR3
  246.     MOV    AREA4.INT_HNDLR,OFFSET INT_HNDLR4
  247.  
  248. ; Save old interrupt vector
  249.     MOV    AH,35H        ; FETCH INTERRUPT VECTOR CONTENTS
  250.     MOV    AL,INT_COM[SI]    ; INTERRUPT NUMBER
  251.     INT    DOS        ; DOS 2 FUNCTION
  252.     MOV    OLD_COM_OFF[SI],BX    ; SAVE
  253.     MOV    BX,ES            ; ES:BX
  254.     MOV    OLD_COM_SEG[SI],BX    ; FOR LATER RESTORATION
  255.     POP    ES        ; RESTORE ES
  256.     pop si
  257.     mov sp,bp
  258.     pop bp
  259.     RET            ; DONE
  260. _save_com    ENDP
  261.     PAGE
  262. ;
  263. ; INSTALL_COM:    INSTALL THE ACTIVE PORT
  264. ;
  265. ; SET 8250 PORTS FROM RS-232 BASE IN ROM BIOS DATA AREA
  266. ; INITIALIZE PORT CONSTANTS AND ERROR COUNTS
  267. ; INSTALL INTERRUPT VECTOR
  268. ;
  269. ;    return ax=1 on success ax=0 on failure
  270. ;
  271. _install_com    PROC FAR
  272.     push bp
  273.     mov bp,sp
  274.     push si
  275.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  276.     PUSH    ES        ; SAVE EXTRA SEGMENT
  277.     CMP    INSTALLED[SI],1 ; Is port installed on this machine?
  278.      JNE    INSTOK        ; NO, CONTINUE
  279.     JMP    INSTX        ; ELSE JUMP IF ALREADY INSTALLED
  280. ; CLEAR ERROR COUNTS
  281. INSTOK: MOV    WORD PTR EOVFLOW[SI],0    ; BUFFER OVERFLOWS
  282.     MOV    WORD PTR EOVRUN[SI],0    ; RECEIVE OVERRUNS
  283.     MOV    WORD PTR EBREAK[SI],0    ; BREAK CHARS
  284.     MOV    WORD PTR EFRAME[SI],0    ; FRAMING ERRORS
  285.     MOV    WORD PTR EPARITY[SI],0    ; PARITY ERRORS
  286.     MOV    WORD PTR EXMIT[SI],0    ; TRANSMISSION ERRORS
  287.     MOV    WORD PTR EDSR[SI],0    ; DATA SET READY ERRORS
  288.     MOV    WORD PTR ECTS[SI],0    ; CLEAR TO SEND ERRORS
  289. ; SENSE PC TYPE AND SET DIVISOR ACCORDINGLY
  290.     MOV    BX,ROM        ; HIGH ROM SEGMENT
  291.     MOV    ES,BX        ; TO ES
  292.     ASSUME    ES:ROM
  293.     MOV    DIV50,DIV50PC    ; ASSUME PC OR XT
  294.     CMP    ROMID,0FDH    ; IS IT A PCjr?
  295.      JNE    INST0        ; JUMP IF NOT
  296.     MOV    DIV50,DIV50JR    ; ELSE SET JR DIVISOR
  297. ; SET 8250 PORT ADDRESSES
  298. INST0:    MOV    BX,RBDA     ; ROM BIOS DATA AREA
  299.     MOV    ES,BX        ; TO ES
  300.     ASSUME    ES:RBDA
  301.     CMP    PORT[SI],1    ; PORT 1?
  302.      JE    INST3F8     ; Yes
  303.     CMP    PORT[SI],2    ; PORT 2?
  304.      JE    INST2F8     ; Yes
  305.     CMP    PORT[SI],3    ; PORT 3?
  306.      JE    INST3E8     ; Yes
  307.     CMP    PORT[SI],4    ; PORT 4?
  308.      JE    INST2E8     ; Yes
  309.     INT    20H        ; N.O.T.A. (Caller is screwed up badly!)
  310.  
  311. INST3F8:MOV    AX,3F8H     ; COM1 BASE PORT ADDRESS
  312.     JMP    SHORT INST2    ; CONTINUE
  313.  
  314. INST2F8:MOV    AX,2F8H     ; COM2 BASE PORT ADDRESS
  315.     JMP    SHORT INST2    ; CONTINUE
  316.  
  317. INST3E8:
  318.     CMP    RS232_BASE+4,0000H     ; We have information?
  319.     JE    INST3E8_A           ; No --> Use default
  320.     MOV    AX,RS232_BASE+4        ; Yes --> Use provided info
  321.     JMP    SHORT INST2    ; CONTINUE
  322.  
  323. INST3E8_A:
  324.     MOV    AX,3E8H     ; COM3 BASE PORT ADDRESS
  325.     JMP    SHORT INST2    ; CONTINUE
  326.  
  327. INST2E8:
  328.     CMP    RS232_BASE+6,0000H     ; We have information?
  329.     JE    INST2E8_A           ; No --> Use default
  330.     MOV    AX,RS232_BASE+6        ; Yes --> Use provided info
  331.     JMP    SHORT INST2    ; CONTINUE
  332.  
  333. INST2E8_A:
  334.     MOV    AX,2E8H     ; COM4 BASE PORT ADDRESS
  335.     ; Fall into INST2
  336.  
  337. INST2:    CMP    AX,RS232_BASE    ; INSTALLED?
  338.      JE    INST2A        ; JUMP IF SO
  339.     CMP    AX,RS232_BASE+2 ; INSTALLED?
  340.      JE    INST2A        ; JUMP IF SO
  341.     CMP    AX,RS232_BASE+4 ; INSTALLED?
  342.      JE    INST2A        ; JUMP IF SO
  343.     CMP    AX,RS232_BASE+6 ; INSTALLED?
  344.      JNE    INST666     ; JUMP IF NOT
  345.     ; Fall into INST2A
  346.  
  347. INST2A: MOV    BX,DATREG    ; OFFSET OF TABLE OF PORTS
  348.     MOV    CX,7        ; LOOP SIX TIMES
  349. INST3:    MOV    WORD PTR [SI][BX],AX ; SET PORT ADDRESS
  350.     INC    AX        ; NEXT PORT
  351.     ADD    BX,2        ; NEXT WORD ADDRESS
  352.     LOOP    INST3        ; RS232 BASE LOOP
  353. ; RESET VECTOR TO POINT TO OUR HANDLER
  354.     MOV    AREA1.INT_HNDLR,OFFSET INT_HNDLR1   ;;;Aready done in SaveCom
  355.     MOV    AREA2.INT_HNDLR,OFFSET INT_HNDLR2
  356.     MOV    AREA3.INT_HNDLR,OFFSET INT_HNDLR3
  357.     MOV    AREA4.INT_HNDLR,OFFSET INT_HNDLR4
  358.     MOV    AH,25H        ; SET INTERRUPT VECTOR CONTENTS
  359.     MOV    AL,INT_COM[SI]    ; INTERRUPT NUMBER
  360.     MOV    DX,OFFSET DGROUP:INT_HNDLR[SI] ; OUR INTERRUPT HANDLER
  361.     PUSH    DS        ; SAVE DATA SEGMENT
  362.     PUSH    CS        ; COPY CS
  363.     POP    DS        ; TO DS
  364.     INT    DOS        ; DOS FUNCTION
  365.     POP    DS        ; RECOVER DATA SEGMENT
  366. ; PORT INSTALLED
  367. INSTX:    MOV    INSTALLED[SI],1 ; PORT INSTALLED
  368.     POP    ES        ; RESTORE ES
  369.     mov ax,1
  370.     pop si
  371.     mov sp,bp
  372.     pop bp
  373.     RET            ; DONE
  374.  
  375. ; PORT NOT INSTALLED
  376. INST666:MOV    INSTALLED[SI],0 ; PORT NOT INSTALLED ON THIS PC
  377.     POP    ES        ; RESTORE ES
  378.     mov ax,0
  379.     pop si
  380.     mov sp,bp
  381.     pop bp
  382.     RET            ; DONE
  383. _install_com    ENDP
  384.     PAGE
  385. ;
  386. ; RESTORE ORIGINAL INTERRUPT VECTOR
  387. ;
  388. _restore_com    PROC FAR
  389.     push bp
  390.     mov bp,sp
  391.     push si
  392.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  393.     MOV    INSTALLED[SI],0 ; PORT IS NO LONGER INSTALLED
  394.     MOV    AH,25H        ; SET INTERRUPT VECTOR FUNCTION
  395.     MOV    AL,INT_COM[SI]    ; INTERRUPT NUMBER
  396.     MOV    DX,OLD_COM_OFF[SI] ; OLD OFFSET TO DX
  397.     MOV    BX,OLD_COM_SEG[SI] ; OLD SEG
  398.     PUSH    DS        ; SAVE DS
  399.     MOV    DS,BX        ; TO DS
  400.     INT    DOS        ; DOS FUNCTION
  401.     POP    DS        ; RECOVER DS
  402.     pop si
  403.     mov sp,bp
  404.     pop bp
  405.     RET            ; DONE
  406. _restore_com    ENDP
  407.     PAGE
  408. ;
  409. ; OPEN_COM ON CURRENT PORT
  410. ;
  411. ; CLEAR BUFFERS
  412. ; RE-INITIALIZE THE INTEL 8250 UART
  413. ; ENABLE INTERRUPTS ON THE INTEL 8259 INTERRUPT CONTROL CHIP
  414. ;
  415. ; [bp+6] = BAUD RATE
  416. ; [bp+8] = CONNECTION: M(ODEM), D(IRECT)
  417. ; [bp+10] = PARITY:    N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
  418. ; [bp+12] = STOP BITS:    1, 2
  419. ; [bp+14] = XON/XOFF:    E(NABLED), D(ISABLED)
  420. ;
  421. _open_com    PROC FAR
  422.     push bp
  423.     mov bp,sp
  424.     push si
  425.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  426.  
  427.     CLI                ; INTERRUPTS OFF
  428.     mov ax,[bp+6]
  429.     MOV    BAUD_RATE[SI],AX    ; SET
  430.     mov bh,[bp+8]
  431.     MOV    CONNECTION[SI],BH    ;     ARGS
  432.     mov bl,[bp+10]
  433.     MOV    PARITY[SI],BL        ;       IN
  434.     mov ch,[bp+12]
  435.     MOV    STOP_BITS[SI],CH    ;          MEMORY
  436.     mov cl,[bp+14]
  437.     MOV    XON_XOFF[SI],CL
  438.  
  439. ; RESET FLOW CONTROL
  440.     MOV    HOST_OFF[SI],0        ; HOST FLOWING
  441.     MOV    PC_OFF[SI],0        ; PC FLOWING
  442.  
  443. ; RESET BUFFER COUNTS AND POINTERS
  444.     MOV    START_TDATA[SI],0
  445.     MOV    END_TDATA[SI],0
  446.     MOV    START_RDATA[SI],0
  447.     MOV    END_RDATA[SI],0
  448.     MOV    SIZE_TDATA[SI],0
  449.     MOV    SIZE_RDATA[SI],0
  450.  
  451.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  452.     JNZ    OC1            ; SKIP IF SO
  453.     JMP    OCX            ; ELSE ABORT
  454. OC1:
  455. ; RESET THE 8250
  456.     MOV    AL,0
  457.     MOV    DX,MCR[SI]
  458.     OUT    DX,AL
  459.     JMP    $+2        ; I/O DELAY FOR JR
  460.  
  461.     MOV    DX,LSR[SI]    ; RESET LINE STATUS CONDITION
  462.     IN    AL,DX
  463.     JMP    $+2        ; I/O DELAY FOR JR
  464.     MOV    DX,DATREG[SI]    ; RESET RECSIVE DATA CONDITION
  465.     IN    AL,DX
  466.     JMP    $+2        ; I/O DELAY FOR JR
  467.     MOV    DX,MSR[SI]    ; RESET MODEM DELTAS AND CONDITIONS
  468.     IN    AL,DX
  469.  
  470. ; CONVERT PASSED BAUD RATE TO 8250 DIVISOR
  471.     MOV    AX,50        ; 50 BAUD
  472.     MUL    DIV50        ; TIMES ITS DIVISOR
  473.     DIV    BAUD_RATE[SI]    ; OTHER SPEEDS ARE PROPORTIONAL
  474.     MOV    BX,AX        ; RESULT TO BX
  475.  
  476. ; SET 8250 DIVISOR
  477.     MOV    DX,LCR[SI]    ; LINE CONTROL REGISTER
  478.     MOV    AL,80H        ; HI BIT ON
  479.     OUT    DX,AL        ; SET DLAB = 1
  480.     JMP    $+2        ; I/O DELAY FOR JR
  481.     MOV    DX,WORD PTR DLL[SI]    ; LEAST SIGNIFICANT BYTE
  482.     MOV    AL,BL        ; LSB FROM TABLE
  483.     OUT    DX,AL        ; SET LSB ON 8250
  484.     JMP    $+2        ; I/O DELAY FOR JR
  485.     MOV    DX,WORD PTR DLH[SI]    ; MOST SIGNIFICANT BYTE
  486.     MOV    AL,BH        ; MSB FROM TABLE
  487.     OUT    DX,AL        ; SET MSB ON 8250
  488.     JMP    $+2        ; I/O DELAY FOR JR
  489.  
  490. ; SET PARITY AND NUMBER OF STOP BITS
  491.     MOV    AL,03H        ; NONE OR SPACE PARITY IS THE DEFAULT
  492.     CMP    PARITY[SI],'O'  ; ODD PARITY REQUESTED?
  493.     JNE    P1        ; JUMP IF NOT
  494.     MOV    AL,0AH        ; SELECT ODD PARITY
  495.     JMP    SHORT P3    ; CONTINUE
  496. P1:    CMP    PARITY[SI],'E'  ; EVEN PARITY REQUESTED?
  497.     JNE    P2        ; JUMP IF NOT
  498.     MOV    AL,1AH        ; SELECT EVEN PARITY
  499.     JMP    SHORT P3    ; CONTINUE
  500. P2:    CMP    PARITY[SI],'M'  ; MARK PARITY REQUESTED?
  501.     JNE    P3        ; JUMP IF NOT
  502.     MOV    AL,2AH        ; SELECT MARK PARITY
  503. P3:    TEST    STOP_BITS[SI],2 ; 2 STOP BITS REQUESTED?
  504.     JZ    STOP1        ; NO
  505.     OR    AL,4        ; YES
  506. STOP1:    MOV    DX,LCR[SI]    ; LINE CONTROL REGISTER
  507.     OUT    DX,AL        ; SET 8250 PARITY MODE AND DLAB=0
  508.  
  509. ; ENABLE INTERRUPTS ON 8259 AND 8250
  510.     IN    AL,INTA01    ; SET ENABLE BIT ON 8259
  511.     AND    AL,NIRQ[SI]
  512.     OUT    INTA01,AL
  513.     MOV    DX,IER[SI]    ; ENABLE INTERRUPTS ON 8250
  514.     MOV    AL,5        ; RECEIVE & LINE ERROR
  515.     OUT    DX,AL
  516.     JMP    $+2        ; I/O DELAY FOR JR
  517.     MOV    DX,MCR[SI]    ; SET DTR AND ENABLE INT DRIVER
  518.     MOV    AL,0BH
  519.     OUT    DX,AL
  520.  
  521. OCX:    STI            ; INTERRUPTS ON
  522.     pop si
  523.     mov sp,bp
  524.     pop bp
  525.     RET            ; DONE
  526. _open_com    ENDP
  527.     PAGE;
  528. ;
  529. ; void far ioctl_com(int Flags, int Arg1, ...)
  530. ;    Flags have bits saying what to do or change (IGNORED TODAY)
  531. ;    Arg1, ...  are the new values
  532. ;
  533. _ioctl_com PROC FAR
  534.     PUSH BP
  535.     MOV BP,SP
  536.     PUSHF                ; Save interrupt context
  537.     PUSH SI
  538.     MOV SI,CURRENT_AREA        ; Pointer to COMi private area
  539.     CLI                ; Prevent surprises
  540.     TEST INSTALLED[SI],1
  541.      JE IOCTLX            ; No good.  Just return.
  542.     MOV AX,[BP+6]            ; Flags
  543.     ; Check bits here...
  544.     MOV AX,[BP+8]            ; Line speed
  545.     MOV BAUD_RATE[SI],AX        ; Save in parameter block
  546.     CALL Set_Baud            ; Set the baud rate in UART
  547. IOCTLX: POP SI
  548.     POPF                ; Restore interrupt state
  549.     MOV SP,BP
  550.     POP BP
  551.     RET
  552. _ioctl_com    ENDP
  553.     PAGE;
  554. ; ioctl-called routines (internal) ...
  555.  
  556. ; SI:    COMi private block
  557. ;    CALL Set_Baud
  558. ; Returns: (nothing)
  559. ; Clobber: AX, BX, DX
  560.  
  561. Set_Baud PROC NEAR
  562.     MOV AX,50
  563.     MUL DIV50            ; Could be different on a PCJr!
  564.     DIV BAUD_RATE[SI]        ; Get right number for the UART
  565.     MOV BX,AX            ; Save it
  566.     MOV DX,LCR[SI]            ; Line Control Register
  567.     IN AL,DX            ; Get current size, stops, parity,...
  568.     PUSH AX
  569.     OR AL,80H            ; DLAB bit
  570.     OUT DX,AL            ; Talk to the baud rate regs now
  571.     MOV DX,WORD PTR DLL[SI]     ; Least significant byte
  572.     MOV AL,BL            ; New value
  573.     OUT DX,AL            ; To UART
  574.     MOV DX,WORD PTR DLH[SI]     ; Most signifiant byte
  575.     MOV AL,BH            ; New value
  576.     OUT DX,AL
  577.     MOV DX,LCR[SI]            ; Line Control Register
  578.     POP AX
  579.     OUT DX,AL            ; Turn off DLAB, keep saved settings
  580.     RET
  581. Set_Baud ENDP
  582.     PAGE;
  583. ;
  584. ; CLOSE_COM - TURNS OFF INTERRUPTS FROM THE COMMUNICATIONS PORT
  585. ;
  586. _close_com    PROC FAR
  587.     push bp
  588.     mov bp,sp
  589.     push si
  590.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  591.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  592.     JZ    CCX        ; ABORT IF NOT
  593.  
  594. ; TURN OFF 8250
  595.     MOV    DX,IER[SI]
  596.     MOV    AL,0
  597.     OUT    DX,AL
  598.  
  599. ; TURN OFF 8259
  600.     MOV    DX,INTA01
  601.     IN    AL,DX
  602.     OR    AL,IRQ[SI]
  603.     JMP    $+2        ; DELAY FOR AT
  604.     OUT    DX,AL
  605.  
  606. CCX:    pop si
  607.     mov sp,bp
  608.     pop bp
  609.     RET
  610. _close_com    ENDP
  611.     PAGE
  612. ;
  613. ; DTR_OFF - TURNS OFF DTR TO TELL MODEMS THAT THE TERMINAL HAS GONE AWAY
  614. ;        AND TO HANG UP THE PHONE
  615. ;
  616. _dtr_off    PROC FAR
  617.     push bp
  618.     mov bp,sp
  619.     push si
  620.     PUSHF            ; SAVE FLAGS
  621.     PUSH    AX        ; SAVE REGS
  622.     PUSH    DX
  623.     PUSH    SI
  624.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  625.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  626.     JZ    DFX        ; ABORT IF NOT
  627.  
  628.     MOV    DX,MCR[SI]
  629.     MOV    AL,08H        ; DTR OFF, RTS OFF, OUT2 ON
  630.     OUT    DX,AL
  631. DFX:    POP    SI        ; RECOVER REGS
  632.     POP    DX
  633.     POP    AX
  634.     POPF            ; RECOVER FLAGS
  635.     pop si
  636.     mov sp,bp
  637.     pop bp
  638.     RET
  639. _dtr_off    ENDP
  640. ;
  641. ; DTR_ON - TURNS DTR ON
  642. ;
  643. _dtr_on PROC FAR
  644.     push bp
  645.     mov bp,sp
  646.     push si
  647.     PUSHF            ; SAVE FLAGS
  648.     PUSH    AX        ; SAVE REGS
  649.     PUSH    DX
  650.     PUSH    SI
  651.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  652.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  653.     JZ    DNX        ; ABORT IF NOT
  654.  
  655.     MOV    DX,MCR[SI]
  656.     MOV    AL,0BH
  657.     OUT    DX,AL
  658. DNX:    POP    SI        ; RECOVER REGS
  659.     POP    DX
  660.     POP    AX
  661.     POPF            ; RECOVER FLAGS
  662.     pop si
  663.     mov sp,bp
  664.     pop bp
  665.     RET            ; DONE
  666. _dtr_on ENDP
  667.     PAGE
  668. ;
  669. ; R_COUNT - RETURNS NUMBER OF BYTES IN THE RECEIVE BUFFER IN AX
  670. ;          total in DX
  671. ;
  672. _r_count    PROC FAR
  673.     push bp
  674.     mov bp,sp
  675.     push si
  676.     PUSHF            ; SAVE FLAGS
  677.     PUSH    SI        ; SAVE SI
  678.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  679.     MOV    AX,0        ; NOTHING RECEIVED IF NOT INSTALLED
  680.     mov dx,R_SIZE
  681.  
  682.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  683.     JZ    RCX        ; ABORT IF NOT
  684.  
  685.     MOV    AX,SIZE_RDATA[SI] ; GET NUMBER OF BYTES USED
  686. RCX:    POP    SI        ; RESTORE SI
  687.     POPF            ; RESTORE FLAGS
  688.     pop si
  689.     mov sp,bp
  690.     pop bp
  691.     RET
  692. _r_count    ENDP
  693.     PAGE
  694. ;
  695. ; RECEIVE - RETURNS THE NEXT CHARACTER FROM THE RECEIVE BUFFER IN AL
  696. ;         AND REMOVES IT FROM THE BUFFER
  697. ;         THE PARITY BIT IS STRIPPED OFF
  698. ;
  699. _receive_com    PROC FAR
  700.     push bp
  701.     mov bp,sp
  702.     push si
  703.     PUSHF                ; SAVE FLAGS
  704.     PUSH    BX            ; SAVE REGS
  705.     PUSH    SI
  706.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  707.     mov    ax,-1 ; -1 if bad call
  708.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  709.     JZ    RCVX            ; ABORT IF NOT
  710.     CMP    SIZE_RDATA[SI],0    ; ANY CHARACTERS?
  711.     JE    RCVX            ; ABORT IF NOT
  712.  
  713. ; GOOD CALL
  714.     mov ah,0    ; good call
  715.     MOV    BX,START_RDATA[SI]    ; GET POINTER TO OLDEST CHAR
  716.     MOV    AL,RDATA[SI][BX]    ; GET CHAR FROM BUFFER
  717. ; MOD BY LBA, 10/6/85 FOR PROPER SUPPORT OF NO PARITY COMMUNICATIONS
  718.     CMP    PARITY[SI],'N'          ; ARE WE RUNNING WITH NO PARITY?
  719.     JE    L11            ; IF SO, DON'T STRIP HIGH BIT
  720. ; END OF MOD
  721.     AND    AL,7FH            ; STRIP PARITY BIT
  722. L11:    INC    BX            ; BUMP START_RDATA
  723.     CMP    BX,R_SIZE        ; SEE IF PAST END
  724.     JB    L12            ; IF NOT THEN SKIP
  725.     MOV    BX,0            ; ADJUST TO BEGINNING
  726. L12:    MOV    START_RDATA[SI],BX    ; SAVE THE NEW START_RDATA VALUE
  727.     DEC    SIZE_RDATA[SI]        ; ONE LESS CHARACTER
  728.     CMP    XON_XOFF[SI],'E'        ; FLOW CONTROL ENABLED?
  729.     JNE    RCVX            ; DO NOTHING IF DISABLED
  730.     CMP    HOST_OFF[SI],1        ; HOST TURNED OFF?
  731.     JNE    RCVX            ; JUMP IF NOT
  732.     CMP    SIZE_RDATA[SI],R_SIZE/20 ; RECEIVE BUFFER NEARLY EMPTY?
  733.     JGE    RCVX            ; DONE IF NOT
  734.     MOV    HOST_OFF[SI],0        ; TURN ON HOST IF SO
  735.     PUSH    AX            ; SAVE RECEIVED CHAR
  736.     MOV    AL,CONTROL_Q        ; TELL HIM TO TALK
  737.     CLI                ; TURN OFF INTERRUPTS
  738.     CALL    SENDII            ; SEND IMMEDIATELY INTERNAL
  739.     STI                ; INTERRUPTS BACK ON
  740.     POP    AX            ; RESTORE RECEIVED CHAR
  741. RCVX:    POP    SI            ; RECOVER REGS
  742.     POP    BX
  743.     POPF                ; RECOVER FLAGS
  744.     pop si
  745.     mov sp,bp
  746.     pop bp
  747.     RET                ; DONE
  748. _receive_com    ENDP
  749.     PAGE
  750. ;
  751. ; S_COUNT - RETURNS IN AX THE AMOUNT OF FREE SPACE
  752. ;           REMAINING IN THE TRANSMIT BUFFER
  753. ;     DX total size
  754. ;
  755. _s_count    PROC FAR
  756.     push bp
  757.     mov bp,sp
  758.     push si
  759.     PUSHF            ; SAVE FLAGS
  760.     PUSH    SI        ; SAVE SI
  761.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  762.     MOV    AX,0        ; NO SPACE LEFT IF NOT INSTALLED
  763.     mov dx,S_SIZE
  764.  
  765.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  766.     JZ    SCX        ; ABORT IF NOT
  767.  
  768.     MOV    AX,S_SIZE    ; GET THE SIZE OF THE X-MIT BUFFER
  769.     SUB    AX,SIZE_TDATA[SI] ; SUBTRACT THE NUMBER OF BYTES USED
  770. SCX:    POP    SI        ; RECOVER SI
  771.     POPF            ; RESTORE FLAGS
  772.     pop si
  773.     mov sp,bp
  774.     pop bp
  775.     RET
  776. _s_count    ENDP
  777.     PAGE
  778. ;
  779. ; SEND - SEND A CHARACTER
  780. ;    [bp+6] = char
  781. ;
  782. _send_com    PROC FAR
  783.     push bp
  784.     mov bp,sp
  785.     push si
  786.     mov al,[bp+6]
  787.     PUSHF                ; SAVE FLAGS
  788.     PUSH    AX            ; SAVE REGS
  789.     PUSH    BX
  790.     PUSH    DX
  791.     PUSH    SI
  792.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  793.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  794.     JZ    L44            ; ABORT IF NOT
  795.  
  796.     CMP    SIZE_TDATA[SI],S_SIZE    ; BUFFER FULL?
  797.     JL    L4A            ; JUMP IF NOT
  798.     INC    WORD PTR EOVFLOW[SI]    ; BUMP ERROR COUNT
  799.     JMP    SHORT L44        ; PUNT
  800. L4A:    MOV    BX,END_TDATA[SI]    ; BX POINTS TO FREE SPACE
  801.     MOV    TDATA[SI][BX],AL    ; MOVE CHAR TO BUFFER
  802.     INC    BX            ; INCREMENT END_TDATA
  803.     CMP    BX,S_SIZE        ; SEE IF PAST END
  804.     JL    L4            ; IF NOT THEN SKIP
  805.     MOV    BX,0            ; ADJUST TO BEGINNING
  806. L4:    MOV    END_TDATA[SI],BX    ; SAVE NEW END_TDATA
  807.     INC    SIZE_TDATA[SI]        ; ONE MORE CHARACTER IN X-MIT BUFFER
  808.     MOV    DX,IER[SI]        ; INTERRUPT ENABLE REGISTER
  809.     IN    AL,DX            ; GET IT
  810.     TEST    AL,2            ; SEE IF TX INTERRUPTS ARE ENABLED
  811.     JNZ    L44            ; JUMP IF SO
  812.     MOV    AL,7            ; IF NOT THEN RCV, TX, LINE ERROR
  813.     OUT    DX,AL            ; ARE ENABLED
  814. L44:    POP    SI            ; RESTORE REGS
  815.     POP    DX
  816.     POP    BX
  817.     POP    AX
  818.     POPF                ; RESTORE FLAGS
  819.     pop si
  820.     mov sp,bp
  821.     pop bp
  822.     RET                ; DONE
  823. _send_com    ENDP
  824.     PAGE
  825. ;
  826. ; SENDI - SEND A CHARACTER IMMEDIATELY
  827. ; [bp+6] = char to send
  828. ;
  829. _sendi_com    PROC FAR
  830.     push bp
  831.     mov bp,sp
  832.     push si
  833.     mov al,[bp+6]
  834.     PUSHF                ; SAVE FLAGS
  835.     PUSH    AX            ; SAVE REGS
  836.     PUSH    BX
  837.     PUSH    DX
  838.     PUSH    SI
  839.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  840.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  841.     JZ    LQ44            ; ABORT IF NOT
  842.  
  843.     CLI                ; MASK INTERRUPTS
  844.     CALL    SENDII            ; CALL INTERNAL SEND IMMEDIATE
  845.     STI                ; INTERRRUPTS BACK ON
  846.  
  847. LQ44:    POP    SI            ; RESTORE REGS
  848.     POP    DX
  849.     POP    BX
  850.     POP    AX
  851.     POPF                ; RESTORE FLAGS
  852.     pop si
  853.     mov sp,bp
  854.     pop bp
  855.     RET                ; DONE
  856. _sendi_com    ENDP
  857.     PAGE
  858. ;
  859. ; INTERNAL ROUTINE
  860. ; DEPENDS ON CALLER TO KEEP INTERRUPTS CLEARED AND SET SI
  861. ; SENDI - SEND A CHARACTER IMMEDIATELY (PUT AT BEGINNING OF QUEUE)
  862. ; AL = CHAR TO WRITE
  863. ;
  864. SENDII    PROC    NEAR
  865.     PUSH    DX            ; SAVE DX
  866.     CMP    SIZE_TDATA[SI],S_SIZE    ; BUFFER FULL?
  867.     JB    LI4A            ; JUMP IF NOT
  868.     INC    WORD PTR EOVFLOW[SI]    ; BUMP ERROR COUNT
  869.     MOV    BX,START_TDATA[SI]    ; BX POINTS TO FIRST CHAR IN BUFFER
  870.     MOV    TDATA[SI][BX],AL    ; CLOBBER FIRST CHAR IN BUFFER
  871.     JMP    SHORT LI4B        ; CONTINUE
  872. LI4A:    MOV    BX,START_TDATA[SI]    ; BX POINTS TO FIRST CHAR IN BUFFER
  873.     DEC    BX            ; BACKUP THE PTR
  874.     CMP    BX,-1            ; BEFORE BEGINNING?
  875.     JNE    LI4            ; JUMP IF NOT
  876.     MOV    BX,S_SIZE-1        ; POINT TO END IF SO
  877. LI4:    MOV    TDATA[SI][BX],AL    ; MOVE CHAR TO BUFFER
  878.     MOV    START_TDATA[SI],BX    ; SAVE NEW START_TDATA
  879.     INC    SIZE_TDATA[SI]        ; ONE MORE CHARACTER IN X-MIT BUFFER
  880. LI4B:    MOV    DX,IER[SI]        ; INTERRUPT ENABLE REGISTER
  881.     IN    AL,DX            ; GET IT
  882.     TEST    AL,2            ; SEE IF TX INTERRUPTS ARE ENABLED
  883.     JNZ    LI44            ; JUMP IF SO
  884.     MOV    AL,7            ; IF NOT THEN RCV, TX, LINE ERROR
  885.     OUT    DX,AL            ; ARE ENABLED
  886. LI44:    POP    DX            ; RECOVER DX
  887.     RET                ; DONE
  888. SENDII    ENDP
  889.     PAGE
  890. ;
  891. ; S_LOCAL
  892. ;
  893. _send_local    PROC FAR
  894.     push bp
  895.     mov bp,sp
  896.     push si
  897.     mov al,[bp+6]
  898.     PUSHF                ; SAVE FLAGS
  899.     PUSH    AX            ; SAVE REGS
  900.     PUSH    BX
  901.     PUSH    SI
  902.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  903.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  904.     JZ    SLX            ; ABORT IF NOT
  905.  
  906.     CLI                ; INTERRUPTS OFF
  907.     CMP    SIZE_RDATA[SI],R_SIZE    ; SEE IF ANY ROOM
  908.     JB    L13A            ; SKIP IF ROOM
  909.     INC    WORD PTR EOVFLOW[SI]    ; BUMP OVERFLOW COUNT
  910.     JMP    SHORT L14        ; PUNT
  911. L13A:    MOV    BX,END_RDATA[SI]    ; BX POINTS TO FREE SPACE
  912.     MOV    RDATA[SI][BX],AL    ; SEND DATA TO BUFFER
  913.     INC    BX            ; INCREMENT END_RDATA POINTER
  914.     CMP    BX,R_SIZE        ; SEE IF GONE PAST END
  915.     JL    L13            ; IF NOT THEN SKIP
  916.     MOV    BX,0            ; ELSE ADJUST TO BEGINNING
  917. L13:    MOV    END_RDATA[SI],BX    ; SAVE VALUE
  918.     INC    SIZE_RDATA[SI]        ; GOT ONE MORE CHARACTER
  919. L14:    STI                ; INTERRUPTS BACK ON
  920.  
  921. SLX:    POP    SI            ; RECOVER REGS
  922.     POP    BX
  923.     POP    AX
  924.     POPF                ; RECOVER FLAGS
  925.     pop si
  926.     mov sp,bp
  927.     pop bp
  928.     RET                ; DONE
  929. _send_local    ENDP
  930.     PAGE
  931. ;
  932. ; BREAK - CAUSES A BREAK TO BE SENT OUT ON THE LINE
  933. ;
  934. _break_com    PROC FAR
  935.     push bp
  936.     mov bp,sp
  937.     push si
  938.     PUSHF            ; SAVE FLAGS
  939.     PUSH    AX        ; SAVE REGS
  940.     PUSH    CX
  941.     PUSH    DX
  942.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  943.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  944.     JZ    BRX        ; ABORT IF NOT
  945.  
  946.     MOV    DX,LCR[SI]    ; LINE CONTROL REGISTER
  947.     IN    AL,DX        ; GET CURRENT SETTING
  948.     JMP    $+2        ; I/O DELAY FOR JR
  949.     OR    AL,40H        ; TURN ON BREAK BIT
  950.     OUT    DX,AL        ; SET IT ON THE 8250
  951.     MOV    CX,0C000H    ; WAIT APPROX. 1/4 SEC.
  952. BREAK1: LOOP    BREAK1        ; BUSY WAIT
  953.     AND    AL,0BFH     ; TURN OFF BREAK BIT
  954.     OUT    DX,AL        ; RESTORE LINE CONTROL REGISTER
  955. BRX:    POP    DX        ; RECOVER REGS
  956.     POP    CX
  957.     POP    AX
  958.     POPF            ; RECOVER FLAGS
  959.     pop si
  960.     mov sp,bp
  961.     pop bp
  962.     RET            ; DONE
  963. _break_com    ENDP
  964.     PAGE
  965. ;
  966. ; COM_ERRORS - RETURN POINTER IN dx:ax TO ERROR COUNTS
  967. ;
  968. _com_errors    PROC FAR
  969.     push bp
  970.     mov bp,sp
  971.     mov ax,OFFSET DGROUP:CURRENT_AREA
  972.     add ax,ERROR_BLOCK
  973.     mov dx,ds
  974.     mov sp,bp
  975.     pop bp
  976.     RET            ; DONE
  977. _com_errors    ENDP
  978.     PAGE
  979. ;
  980. ; INTERNAL ROUTINE
  981. ; BUMP ERROR COUNTS FROM LINE STATUS IN AL
  982. ;
  983. E_BUMP    PROC    NEAR
  984.     TEST    AL,2        ; OVERRUN ERROR?
  985.     JZ    LSI1        ; JUMP IF NOT
  986.     INC    WORD PTR EOVRUN[SI]    ; ELSE BUMP ERROR COUNT
  987. LSI1:    TEST    AL,4        ; PARITY ERROR?
  988.     JZ    LSI2        ; JUMP IF NOT
  989.     INC    WORD PTR EPARITY[SI]    ; ELSE BUMP ERROR COUNT
  990. LSI2:    TEST    AL,8        ; FRAMING ERROR?
  991.     JZ    LSI3        ; JUMP IF NOT
  992.     INC    WORD PTR EFRAME[SI]    ; ELSE BUMP ERROR COUNT
  993. LSI3:    TEST    AL,16        ; BREAK RECEIVED?
  994.     JZ    LSI4        ; JUMP IF NOT
  995.     INC    WORD PTR EBREAK[SI]    ; ELSE BUMP ERROR COUNT
  996. LSI4:    RET            ; DONE
  997. E_BUMP    ENDP
  998.     PAGE
  999. ;
  1000. ; INTERNAL ROUTINE
  1001. ; MODEM SEND PROTOCOL
  1002. ;
  1003. M_PROTOCOL PROC NEAR
  1004.     CMP    CONNECTION[SI],'M' ; MODEM CONNECTION?
  1005.     JNE    S3        ; IF NOT, SKIP DSR & CTS PROTOCOL
  1006.  
  1007. ; TELL MODEM WE'RE READY TO SEND
  1008.     MOV    DX,MCR[SI]    ; MODEM CONTROL REGISTER
  1009.     MOV    AL,00001011B    ; OUT 2, RTS, DTR
  1010.     OUT    DX,AL        ; TERMINAL READY, REQUEST TO SEND
  1011.     JMP    $+2        ; I/O DELAY FOR JR
  1012.  
  1013. ; WAIT UNTIL MODEM SAYS DATA SET READY
  1014.     MOV    CX,1000     ; TIMEOUT COUNT
  1015.     MOV    DX,MSR[SI]    ; MODEM STATUS REGISTER
  1016. S1:    IN    AL,DX        ; GET MODEM STATUS
  1017.     TEST    AL,20H        ; DATA SET READY?
  1018.     JNZ    S1X        ; YES, TEST CLEAR TO SEND
  1019.     LOOP    S1        ; NO, BUSY WAIT
  1020.     INC    WORD PTR EDSR[SI]    ; BUMP ERROR COUNT
  1021.     JMP    SHORT S3    ; WE TIMED OUT
  1022. S1X:
  1023. ; WAIT UNTIL MODEM SAYS IT'S CLEAR TO SEND
  1024.     MOV    CX,1000     ; TIMEOUT COUNT
  1025. S2:    IN    AL,DX        ; GET MODEM STATUS
  1026.     TEST    AL,10H        ; CLEAR TO SEND?
  1027.     JNZ    S2X        ; YES
  1028.     LOOP    S2        ; NO, KEEP TRYING
  1029.     INC    WORD PTR ECTS[SI]    ; BUMP ERROR COUNT - WE TIMED OUT
  1030. S2X:
  1031. ; TEST FOR TRANSMITTER READY
  1032. S3:    MOV    DX,LSR[SI]    ; LINE STATUS REGISTER
  1033.     IN    AL,DX        ; GET LINE STATUS
  1034.     TEST    AL,20H        ; TRANSMITTER READY?
  1035.     JNZ    S4        ; SKIP IF SO
  1036.     INC    WORD PTR EXMIT[SI]    ; ELSE BUMP ERROR COUNT
  1037. S4:    RET            ; DONE
  1038. M_PROTOCOL ENDP
  1039.     PAGE
  1040. ;
  1041. ; INTERNAL ROUTINES FOR FLOW CONTROL
  1042. ;
  1043. ; FLOW_IN - RESPOND TO FLOW CONTROL COMMANDS FROM HOST
  1044. ; FLOW_OUT - ISSUE FLOW CONTROL COMMANDS TO HOST
  1045. ;
  1046. FLOW_IN PROC    NEAR
  1047.     PUSH    AX        ; SAVE CHAR
  1048.     CMP    XON_XOFF[SI],'E'; FLOW CONTROL ENABLED?
  1049.     JNE    FI_NOCARRY    ; DO NOTHING IF DISABLED
  1050.     AND    AL,7FH        ; STRIP PARITY
  1051.     CMP    AL,CONTROL_S    ; STOP COMMAND RECEIVED?
  1052.     JNE    FI_1        ; JUMP IF NOT
  1053.     MOV    PC_OFF[SI],1    ; WE MUST SHUT UP
  1054.     STC            ; Flag we got special character
  1055.     JMP    SHORT FI_EXIT    ; Continue
  1056.  
  1057. FI_1:    CMP    AL,CONTROL_Q    ; GO COMMAND RECEIVED?
  1058.     JNE    FI_NOCARRY    ; NO, MUST BE NORMAL CHAR
  1059.     MOV    PC_OFF[SI],0    ; WE START TALKING AGAIN
  1060.     STC            ; Flag we got special character
  1061.     JMP    SHORT FI_EXIT    ; Continue
  1062.  
  1063. FI_NOCARRY:
  1064.     CLC            ; Not special character, no carry
  1065. FI_EXIT:
  1066.     POP    AX        ; RESTORE CHAR
  1067.     RET            ; DONE
  1068. FLOW_IN ENDP
  1069. ;
  1070. FLOW_OUT PROC    NEAR
  1071.     CMP    XON_XOFF[SI],'E'; FLOW CONTROL ENABLED?
  1072.     JNE    FO_X        ; DO NOTHING IF DISABLED
  1073.     CMP    HOST_OFF[SI],1    ; HOST TURNED OFF?
  1074.     JE    FO_X        ; JUMP IF SO
  1075.     CMP    SIZE_RDATA[SI],R_SIZE/2 ; RECEIVE BUFFER NEARLY FULL?
  1076.     JLE    FO_X        ; DONE IF NOT
  1077.     MOV    AL,CONTROL_S    ; TURN OFF HOST IF SO
  1078.     CALL    SENDII        ; SEND IMMEDIATELY INTERNAL
  1079.     MOV    HOST_OFF[SI],1    ; HOST IS NOW OFF
  1080. FO_X:    RET            ; DONE
  1081. FLOW_OUT ENDP
  1082.     PAGE ;
  1083. ;
  1084. ; _MODEM_STATUS - Returns the modem status register in AL
  1085. ;
  1086. ; Bits are:    0x80:    -CD    (Carrier Detect, inverted)
  1087. ;        0x40:    -RI    (Ring Indicator, inverted)
  1088. ;        0x20:    -DSR    (Data Set Ready, inverted)
  1089. ;        0x10:    -CTS    (Clear to Send, inverted)
  1090. ;        0x08:    Delta Carrier Detect    (CD changed)
  1091. ;        0x04:    Trailing edge of RI    (RI went OFF)
  1092. ;        0x02:    Delta DSR        (DSR changed)
  1093. ;        0x01:    Delta CTS        (CTS changed)
  1094. ;
  1095. _modem_status    PROC FAR
  1096.     push bp
  1097.     mov bp,sp
  1098.     PUSH DX
  1099.     PUSH SI
  1100.     MOV SI,CURRENT_AREA        ; Point to block for selected port
  1101.     MOV DX,MSR[SI]            ; IO Addr of Modem Status Register
  1102.     IN AL,DX            ; Get the live value
  1103.     XOR AH,AH            ; Flush unwanted bits
  1104.     POP SI
  1105.     POP DX
  1106.     mov sp,bp
  1107.     pop bp
  1108.     RET
  1109. _modem_status    ENDP
  1110.     PAGE
  1111. ;
  1112. ; INT_HNDLR1 - HANDLES INTERRUPTS GENERATED BY COM1:
  1113. ;
  1114. INT_HNDLR1 PROC  FAR
  1115.     PUSH    SI        ; SAVE SI
  1116.     MOV    SI,OFFSET DGROUP:AREA1    ; DATA AREA FOR COM1:
  1117.     JMP    SHORT INT_COMMON ; CONTINUE
  1118. ;
  1119. ; INT_HNDLR2 - HANDLES INTERRUPTS GENERATED BY COM2:
  1120. ;
  1121. INT_HNDLR2 PROC  FAR
  1122.     PUSH    SI        ; SAVE SI
  1123.     MOV    SI,OFFSET DGROUP:AREA2    ; DATA AREA FOR COM2:
  1124.     JMP    SHORT INT_COMMON ; CONTINUE
  1125. ;
  1126. ; INT_HNDLR3 - HANDLES INTERRUPTS GENERATED BY COM3:
  1127. ;
  1128. INT_HNDLR3 PROC  FAR
  1129.     PUSH    SI        ; SAVE SI
  1130.     MOV    SI,OFFSET DGROUP:AREA3    ; DATA AREA FOR COM3:
  1131.     JMP    SHORT INT_COMMON ; CONTINUE
  1132. ;
  1133. ; INT_HNDLR4 - HANDLES INTERRUPTS GENERATED BY COM4:
  1134. ;
  1135. INT_HNDLR4 PROC  FAR
  1136.     PUSH    SI        ; SAVE SI
  1137.     MOV    SI,OFFSET DGROUP:AREA4    ; DATA AREA FOR COM4:
  1138.     ; Fall into INT_COMMON
  1139.  
  1140. ;
  1141. ; BODY OF INTERRUPT HANDLER
  1142. ;
  1143. INT_COMMON:
  1144.     PUSH    AX        ; SAVE REGS
  1145.     PUSH    BX
  1146.     PUSH    CX
  1147.     PUSH    DX
  1148.     PUSH    BP
  1149.     PUSH    DI
  1150.     PUSH    DS
  1151.     PUSH    ES
  1152.  
  1153.     MOV AX,DGROUP        ; Offsets are relative to DGROUP [WWP]
  1154.     MOV    DS,AX        ; TO DS
  1155.  
  1156. ; CLEAR THE INTERRUPT CONTROLLER FLAG
  1157.     MOV    DX,INTA00    ; 8259 CONTROL PORT
  1158.     MOV    AL,EOI[SI]    ; SPECIFIC END OF INTERRUPT
  1159.     OUT    DX,AL        ; CLEAR FLAG
  1160.  
  1161. ; FIND OUT WHERE INTERRUPT CAME FROM AND JUMP TO ROUTINE TO HANDLE IT
  1162. REPOLL:
  1163.     MOV    DX,IIR[SI]    ; READ INTERRUPT STATUS REGISTER
  1164.     IN    AL,DX
  1165.     CMP    AL,4
  1166.     JE    RX_INT        ; IF FROM THE RECEIVER
  1167.     CMP    AL,2
  1168.     JE    TX_INT        ; IF FROM THE TRANSMITTER
  1169.     CMP    AL,6
  1170.     JE    LSTAT_INT    ; INTERRUPT BECAUSE OF LINE STATUS
  1171.     CMP    AL,0
  1172.     JE    MSTAT_INT    ; INTERRUPT BECAUSE OF MODEM STATUS
  1173.     JMP    FAR PTR INT_END ; DONE, EXIT (DON'T FIX FAR PTR STUFF)
  1174.  
  1175. LSTAT_INT:
  1176.     MOV    DX,LSR[SI]    ; READ AND IGNORE LINE STATUS
  1177.     IN    AL,DX        ;
  1178.     CALL    E_BUMP        ; JUST BUMP ERROR COUNTS
  1179.     JMP    REPOLL        ; SEE IF ANY MORE INTERRUPTS
  1180.  
  1181. MSTAT_INT:
  1182.     MOV    DX,MSR[SI]    ; READ AND IGNORE MODEM STATUS
  1183.     IN    AL,DX        ;
  1184.     JMP    REPOLL        ; SEE IF ANY MORE INTERRUPTS
  1185.  
  1186. TX_INT:
  1187.     CMP    PC_OFF[SI],1    ; HAVE WE BEEN TOLD TO SHUT UP?
  1188.     JNE    GOODTX1     ; JUMP IF NOT
  1189.     CMP    HOST_OFF[SI],1    ; HAS HOST ALSO SHUT UP?
  1190.     JNE    SEND_NO_MORE    ; JUMP IF NOT
  1191.  
  1192. ; CLEAR XON/XOFF DEADLOCK
  1193.     MOV    PC_OFF[SI],0    ; WE SPEAK
  1194.     MOV    HOST_OFF[SI],0    ; THEY REPLY
  1195.     MOV    AL,CONTROL_Q    ; BUT ONLY WHEN
  1196.     CALL    SENDII        ; WE LET THEM
  1197.  
  1198. GOODTX1:
  1199.     CMP    SIZE_TDATA[SI],0 ; SEE IF ANY MORE DATA TO SEND
  1200.     JG    HAVE_DATA    ; IF POSITIVE THEN THERE IS DATA TO SEND
  1201.  
  1202. ; IF NO DATA TO SEND THEN RESET TX INTERRUPT AND RETURN
  1203. SEND_NO_MORE:
  1204.     MOV    DX,IER[SI]        ;
  1205.     MOV    AL,5            ; JUST RCV AND LINE ERROR
  1206.     OUT    DX,AL            ; ARE SET
  1207.     JMP    REPOLL            ;
  1208.  
  1209. HAVE_DATA:
  1210.     CALL    M_PROTOCOL        ; DO MODEM PROTOCOL IF NECESSARY
  1211.  
  1212.     MOV    BX,START_TDATA[SI]    ; BX POINTS TO NEXT CHAR. TO BE SENT
  1213.     MOV    AL,TDATA[SI][BX]    ; GET DATA FROM BUFFER
  1214.     MOV    DX,DATREG[SI]        ; DX EQUALS PORT TO SEND DATA TO
  1215.     OUT    DX,AL            ; SEND DATA
  1216.     INC    BX            ; INCREMENT START_TDATA
  1217.     CMP    BX,S_SIZE        ; SEE IF GONE PAST END
  1218.     JB    NTADJ            ; IF NOT THEN SKIP
  1219.     MOV    BX,0            ; RESET TO BEGINNING
  1220. NTADJ:    MOV    START_TDATA[SI],BX    ; SAVE START_TDATA
  1221.     DEC    SIZE_TDATA[SI]        ; ONE LESS CHARACTER IN X-MIT BUFFER
  1222.     JMP    REPOLL
  1223.  
  1224. RX_INT:
  1225.     MOV    DX,DATREG[SI]        ; 8250 DATA REGISTER
  1226.     IN    AL,DX            ; GET DATA
  1227.     CALL    FLOW_IN         ; RESPOND TO F.C. COMMANDS FROM HOST
  1228.     JC    REPOLL            ; If flow control, do not save
  1229.                     ; ahd
  1230.     CMP    SIZE_RDATA[SI],R_SIZE    ; SEE IF ANY ROOM
  1231.     JL    GOOD_RX1        ; CONTINUE IF SO
  1232.     INC    WORD PTR EOVFLOW[SI]    ; BUMP OVERFLOW ERROR COUNT
  1233.     JMP    REPOLL            ; PUNT
  1234. GOOD_RX1:
  1235.     MOV    BX,END_RDATA[SI]    ; BX POINTS TO FREE SPACE
  1236.     MOV    RDATA[SI][BX],AL    ; MOVE DATA TO BUFFER
  1237.     INC    SIZE_RDATA[SI]        ; GOT ONE MORE CHARACTER
  1238.     INC    BX            ; INCREMENT END_RDATA POINTER
  1239.     CMP    BX,R_SIZE        ; SEE IF GONE PAST END
  1240.     JB    NRADJ            ; IF NOT THEN SKIP
  1241.     MOV    BX,0            ; ELSE ADJUST TO BEGINNING
  1242. NRADJ:    MOV    END_RDATA[SI],BX    ; SAVE VALUE
  1243. DO_FLOW:                ; ahd
  1244.     CALL    FLOW_OUT        ; ISSUE FLOW CONTROL COMMANDS TO HOST
  1245.     JMP    REPOLL            ;
  1246.  
  1247. INT_END:
  1248.     POP    ES        ; RESTORE REGS
  1249.     POP    DS
  1250.     POP    DI
  1251.     POP    BP
  1252.     POP    DX
  1253.     POP    CX
  1254.     POP    BX
  1255.     POP    AX
  1256.  
  1257.     POP    SI        ; RESTORE SI, TOO
  1258.     IRET
  1259. INT_HNDLR4 ENDP
  1260. INT_HNDLR3 ENDP
  1261. INT_HNDLR2 ENDP
  1262. INT_HNDLR1 ENDP
  1263. COM_TEXT    ENDS
  1264.     END
  1265.